  <!DOCTYPE html>
  <html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="generator" content="pandoc" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
    <title>GTK 4 tutorial</title>
    <style>
      code{white-space: pre-wrap;}
      span.smallcaps{font-variant: small-caps;}
      span.underline{text-decoration: underline;}
      div.column{display: inline-block; vertical-align: top; width: 50%;}
      div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
      ul.task-list{list-style: none;}
      pre{overflow: visible;}
      pre > code.sourceCode { white-space: pre; position: relative; }
      pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
      pre > code.sourceCode > span:empty { height: 1.2em; }
      code.sourceCode > span { color: inherit; text-decoration: inherit; }
      div.sourceCode { margin: 1em 0; }
      pre.sourceCode { margin: 0; }
      @media screen {
      div.sourceCode { overflow: auto; }
      }
      @media print {
      pre > code.sourceCode { white-space: pre-wrap; }
      pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
      }
      pre.numberSource code
        { counter-reset: source-line 0; }
      pre.numberSource code > span
        { position: relative; left: -4em; counter-increment: source-line; }
      pre.numberSource code > span > a:first-child::after
        { content: counter(source-line);
          position: relative; left: -1em; text-align: right; vertical-align: baseline;
          border: none; display: inline-block;
          -webkit-touch-callout: none; -webkit-user-select: none;
          -khtml-user-select: none; -moz-user-select: none;
          -ms-user-select: none; user-select: none;
          padding: 0 4px; width: 4em;
          color: #aaaaaa;
        }
      pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa;  padding-left: 4px; }
      div.sourceCode
        {   }
      @media screen {
      pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
      }
      code span.al { color: #ff0000; font-weight: bold; } /* Alert */
      code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
      code span.at { color: #7d9029; } /* Attribute */
      code span.bn { color: #40a070; } /* BaseN */
      code span.bu { } /* BuiltIn */
      code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
      code span.ch { color: #4070a0; } /* Char */
      code span.cn { color: #880000; } /* Constant */
      code span.co { color: #60a0b0; font-style: italic; } /* Comment */
      code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
      code span.do { color: #ba2121; font-style: italic; } /* Documentation */
      code span.dt { color: #902000; } /* DataType */
      code span.dv { color: #40a070; } /* DecVal */
      code span.er { color: #ff0000; font-weight: bold; } /* Error */
      code span.ex { } /* Extension */
      code span.fl { color: #40a070; } /* Float */
      code span.fu { color: #06287e; } /* Function */
      code span.im { } /* Import */
      code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
      code span.kw { color: #007020; font-weight: bold; } /* Keyword */
      code span.op { color: #666666; } /* Operator */
      code span.ot { color: #007020; } /* Other */
      code span.pp { color: #bc7a00; } /* Preprocessor */
      code span.sc { color: #4070a0; } /* SpecialChar */
      code span.ss { color: #bb6688; } /* SpecialString */
      code span.st { color: #4070a0; } /* String */
      code span.va { color: #19177c; } /* Variable */
      code span.vs { color: #4070a0; } /* VerbatimString */
      code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
      div.sourceCode { margin: 10px; padding: 16px 10px 8px 10px; border: 2px solid silver; background-color: ghostwhite; overflow-x:scroll}
      pre:not(.sourceCode) { margin: 10px; padding: 16px 10px 8px 10px; border: 2px solid silver; background-color: ghostwhite; overflow-x:scroll}
      table {margin-left: auto; margin-right: auto; border-collapse: collapse; border: 1px solid;}
      th {padding: 2px 6px; border: 1px solid; background-color: ghostwhite;}
      td {padding: 2px 6px; border: 1px solid;}
      img {display: block; margin-left: auto; margin-right: auto;}
      figcaption {text-align: center;}
    </style>
  </head>
  <body style="padding-top: 70px;">
    <div class="container">
    <nav class="navbar fixed-top navbar-expand-lg navbar-dark bg-primary">
      <div class="container-fluid">
        <span class="navbar-brand">Gtk4 tutorial</span>
        <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
          <span class="navbar-toggler-icon"></span>
        </button>
        <div class="collapse navbar-collapse" id="navbarSupportedContent">
          <ul class="navbar-nav me-auto mb-2 mb-lg-0">
            <li class="nav-item">
<a class="nav-link" href="index.html">Home</a>
</li>

            <li class="nav-item">
<a class="nav-link" href="sec14.html">Prev: section14</a>
</li>

            <li class="nav-item">
<a class="nav-link" href="sec16.html">Next: section16</a>
</li>

          </ul>
        </div>
      </div>
    </nav>
<h1 id="tfeapplication.c">tfeapplication.c</h1>
<p><code>tfeapplication.c</code> includes all the code other than
<code>tfetxtview.c</code> and <code>tfenotebook.c</code>. It does:</p>
<ul>
<li>Application support, mainly handling command line arguments.</li>
<li>Builds widgets using ui file.</li>
<li>Connects button signals and their handlers.</li>
<li>Manages CSS.</li>
</ul>
<h2 id="main">main</h2>
<p>The function <code>main</code> is the first invoked function in C
language. It connects the command line given by the user and Gtk
application.</p>
<div class="sourceCode" id="cb1"><pre
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb1-1"><a href="#cb1-1"></a><span class="pp">#define APPLICATION_ID </span><span class="st">&quot;com.github.ToshioCP.tfe&quot;</span></span>
<span id="cb1-2"><a href="#cb1-2"></a></span>
<span id="cb1-3"><a href="#cb1-3"></a><span class="dt">int</span></span>
<span id="cb1-4"><a href="#cb1-4"></a>main <span class="op">(</span><span class="dt">int</span> argc<span class="op">,</span> <span class="dt">char</span> <span class="op">**</span>argv<span class="op">)</span> <span class="op">{</span></span>
<span id="cb1-5"><a href="#cb1-5"></a>  GtkApplication <span class="op">*</span>app<span class="op">;</span></span>
<span id="cb1-6"><a href="#cb1-6"></a>  <span class="dt">int</span> stat<span class="op">;</span></span>
<span id="cb1-7"><a href="#cb1-7"></a></span>
<span id="cb1-8"><a href="#cb1-8"></a>  app <span class="op">=</span> gtk_application_new <span class="op">(</span>APPLICATION_ID<span class="op">,</span> G_APPLICATION_HANDLES_OPEN<span class="op">);</span></span>
<span id="cb1-9"><a href="#cb1-9"></a></span>
<span id="cb1-10"><a href="#cb1-10"></a>  g_signal_connect <span class="op">(</span>app<span class="op">,</span> <span class="st">&quot;startup&quot;</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>app_startup<span class="op">),</span> NULL<span class="op">);</span></span>
<span id="cb1-11"><a href="#cb1-11"></a>  g_signal_connect <span class="op">(</span>app<span class="op">,</span> <span class="st">&quot;activate&quot;</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>app_activate<span class="op">),</span> NULL<span class="op">);</span></span>
<span id="cb1-12"><a href="#cb1-12"></a>  g_signal_connect <span class="op">(</span>app<span class="op">,</span> <span class="st">&quot;open&quot;</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>app_open<span class="op">),</span> NULL<span class="op">);</span></span>
<span id="cb1-13"><a href="#cb1-13"></a></span>
<span id="cb1-14"><a href="#cb1-14"></a>  stat <span class="op">=</span>g_application_run <span class="op">(</span>G_APPLICATION <span class="op">(</span>app<span class="op">),</span> argc<span class="op">,</span> argv<span class="op">);</span></span>
<span id="cb1-15"><a href="#cb1-15"></a>  g_object_unref <span class="op">(</span>app<span class="op">);</span></span>
<span id="cb1-16"><a href="#cb1-16"></a>  <span class="cf">return</span> stat<span class="op">;</span></span>
<span id="cb1-17"><a href="#cb1-17"></a><span class="op">}</span></span></code></pre></div>
<ul>
<li>1: Defines the application id. It is easy to find the application
id, and better than the id is embedded in
<code>gtk_application_new</code>.</li>
<li>8: Creates GtkApplication object.</li>
<li>10-12: Connects “startup”, “activate” and “open” signals to their
handlers.</li>
<li>14: Runs the application.</li>
<li>15-16: releases the reference to the application and returns the
status.</li>
</ul>
<h2 id="startup-signal-handler">startup signal handler</h2>
<p>Startup signal is emitted just after the GtkApplication instance is
initialized. What the signal handler needs to do is the initialization
of the application.</p>
<ul>
<li>Builds the widgets using ui file.</li>
<li>Connects button signals and their handlers.</li>
<li>Sets CSS.</li>
</ul>
<p>The handler is as follows.</p>
<p>@@<span class="citation" data-cites="include">@include</span>
tfe5/tfeapplication.c app_startup @@@</p>
<ul>
<li>12-15: Builds widgets using ui file (resource). Connects the
top-level window and the application with
<code>gtk_window_set_application</code>.</li>
<li>16-23: Gets buttons and connects their signals and handlers.</li>
<li>24: Releases the reference to GtkBuilder.</li>
<li>26-31: Sets CSS. CSS in Gtk is similar to CSS in HTML. You can set
margin, border, padding, color, font and so on with CSS. In this program
CSS is in line 30. It sets padding, font-family and font size of
GtkTextView.</li>
<li>26-28: GdkDisplay is used to set CSS. CSS will be explained in the
next subsection.</li>
<li>33: Connects “destroy” signal on the main window and before_destroy
handler. This handler is explained in the next subsection.</li>
<li>34: The provider is useless for the startup handler, so
g_object_unref(provider) is called. Note: It doesn’t mean the
destruction of the provider. It is referred by the display so the
reference count is not zero.</li>
</ul>
<h2 id="css-in-gtk">CSS in Gtk</h2>
<p>CSS is an abbreviation of Cascading Style Sheet. It is originally
used with HTML to describe the presentation semantics of a document. You
might have found that the widgets in Gtk is similar to a window in a
browser. It implies that CSS can also be applied to Gtk windowing
system.</p>
<h3 id="css-nodes-selectors">CSS nodes, selectors</h3>
<p>The syntax of CSS is as follows.</p>
<pre><code>selector { color: yellow; padding-top: 10px; ...}</code></pre>
<p>Every widget has CSS node. For example GtkTextView has
<code>textview</code> node. If you want to set style to GtkTextView,
substitute “textview” for the selector.</p>
<pre><code>textview {color: yellow; ...}</code></pre>
<p>Class, ID and some other things can be applied to the selector like
Web CSS. Refer to <a
href="https://docs.gtk.org/gtk4/css-overview.html">GTK 4 API Reference –
CSS in Gtk</a> for further information.</p>
<p>In line 30, the CSS is a string.</p>
<pre><code>textview {padding: 10px; font-family: monospace; font-size: 12pt;}</code></pre>
<ul>
<li>padding is a space between the border and contents. This space makes
the textview easier to read.</li>
<li>font-family is a name of font. “monospace” is one of the generic
family font keywords.</li>
<li>font-size is set to 12pt.</li>
</ul>
<h3 id="gtkstylecontext-gtkcssprovider-and-gdkdisplay">GtkStyleContext,
GtkCSSProvider and GdkDisplay</h3>
<p>GtkStyleContext is an object that stores styling information
affecting a widget. Each widget is connected to the corresponding
GtkStyleContext. You can get the context by
<code>gtk_widget_get_style_context</code>.</p>
<p>GtkCssProvider is an object which parses CSS in order to style
widgets.</p>
<p>To apply your CSS to widgets, you need to add GtkStyleProvider (the
interface of GtkCSSProvider) to GtkStyleContext. However, instead, you
can add it to GdkDisplay of the window (usually top-level window).</p>
<p>Look at the source file of <code>startup</code> handler again.</p>
<ul>
<li>28: The display is obtained by
<code>gtk_widget_get_display</code>.</li>
<li>29: Creates a GtkCssProvider instance.</li>
<li>30: Puts the CSS into the provider.</li>
<li>31: Adds the provider to the display. The last argument of
<code>gtk_style_context_add_provider_for_display</code> is the priority
of the style provider.
<code>GTK_STYLE_PROVIDER_PRIORITY_APPLICATION</code> is a priority for
application-specific style information.
<code>GTK_STYLE_PROVIDER_PRIORITY_USER</code> is also often used and it
is the highest priority. So,
<code>GTK_STYLE_PROVIDER_PRIORITY_USER</code> is often used to a
specific widget.</li>
</ul>
<p>It is possible to add the provider to the context of GtkTextView
instead of GdkDiplay. To do so, rewrite <code>tfe_text_view_new</code>.
First, get the GtkStyleContext object of a TfeTextView object. Then adds
the CSS provider to the context.</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a>GtkWidget <span class="op">*</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>tfe_text_view_new <span class="op">(</span><span class="dt">void</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>  GtkWidget <span class="op">*</span>tv<span class="op">;</span></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a>  tv <span class="op">=</span> gtk_widget_new <span class="op">(</span>TFE_TYPE_TEXT_VIEW<span class="op">,</span> NULL<span class="op">);</span></span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a>  GtkStyleContext <span class="op">*</span>context<span class="op">;</span></span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a>  context <span class="op">=</span> gtk_widget_get_style_context <span class="op">(</span>GTK_WIDGET <span class="op">(</span>tv<span class="op">));</span></span>
<span id="cb5-10"><a href="#cb5-10" aria-hidden="true" tabindex="-1"></a>  GtkCssProvider <span class="op">*</span>provider <span class="op">=</span> gtk_css_provider_new <span class="op">();</span></span>
<span id="cb5-11"><a href="#cb5-11" aria-hidden="true" tabindex="-1"></a>  gtk_css_provider_load_from_data <span class="op">(</span>provider<span class="op">,</span> <span class="st">&quot;textview {padding: 10px; font-family: monospace; font-size: 12pt;}&quot;</span><span class="op">,</span> <span class="op">-</span><span class="dv">1</span><span class="op">);</span></span>
<span id="cb5-12"><a href="#cb5-12" aria-hidden="true" tabindex="-1"></a>  gtk_style_context_add_provider <span class="op">(</span>context<span class="op">,</span> GTK_STYLE_PROVIDER <span class="op">(</span>provider<span class="op">),</span> GTK_STYLE_PROVIDER_PRIORITY_USER<span class="op">);</span></span>
<span id="cb5-13"><a href="#cb5-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-14"><a href="#cb5-14" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> tv<span class="op">;</span></span>
<span id="cb5-15"><a href="#cb5-15" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>CSS in the context takes precedence over CSS in the display.</p>
<p>@@<span class="citation" data-cites="include">@include</span>
tfe5/tfeapplication.c before_destroy @@@</p>
<p>When a widget is destroyed, or more precisely during its dispose
process, a “destroy” signal is emitted. The “before_destroy” handler
connects to the signal on the main window. (See the program list of
app_startup.) So, it is called when the window is destroyed.</p>
<p>The handler removes the CSS provider from the GdkDisplay.</p>
<h2 id="activate-and-open-handler">activate and open handler</h2>
<p>The handler of “activate” and “open” signal are
<code>app_activate</code> and <code>app_open</code> respectively. They
just create a new GtkNotebookPage.</p>
<p>@@<span class="citation" data-cites="include">@include</span>
tfe5/tfeapplication.c app_activate app_open @@@</p>
<ul>
<li>1-10: <code>app_activate</code>.</li>
<li>8-10: Creates a new page and shows the window.</li>
<li>12-25: <code>app_open</code>.</li>
<li>20-21: Creates notebook pages with files.</li>
<li>22-23: If no page has created, maybe because of read error, then it
creates an empty page.</li>
<li>24: Shows the window.</li>
</ul>
<p>These codes have become really simple thanks to tfenotebook.c and
tfetextview.c.</p>
<h2 id="primary-instance">Primary instance</h2>
<p>Only one GApplication instance can be run at a time per session. The
session is a bit difficult concept and also platform-dependent, but
roughly speaking, it corresponds to a graphical desktop login. When you
use your PC, you probably login first, then your desktop appears until
you log off. This is the session.</p>
<p>However, Linux is multi process OS and you can run two or more
instances of the same application. Isn’t it a contradiction?</p>
<p>When first instance is launched, then it registers itself with its
application ID (for example, <code>com.github.ToshioCP.tfe</code>). Just
after the registration, startup signal is emitted, then activate or open
signal is emitted and the instance’s main loop runs. I wrote “startup
signal is emitted just after the application instance is initialized” in
the prior subsection. More precisely, it is emitted just after the
registration.</p>
<p>If another instance which has the same application ID is invoked, it
also tries to register itself. Because this is the second instance, the
registration of the ID has already done, so it fails. Because of the
failure startup signal isn’t emitted. After that, activate or open
signal is emitted in the primary instance, not the second instance. The
primary instance receives the signal and its handler is invoked. On the
other hand, the second instance doesn’t receive the signal and it
immediately quits.</p>
<p>Try to run two instances in a row.</p>
<pre><code>$ ./_build/tfe &amp;
[1] 84453
$ ./build/tfe tfeapplication.c
$</code></pre>
<p>First, the primary instance opens a window. Then, after the second
instance is run, a new notebook page with the contents of
<code>tfeapplication.c</code> appears in the primary instance’s window.
This is because the open signal is emitted in the primary instance. The
second instance immediately quits so shell prompt soon appears.</p>
<h2 id="a-series-of-handlers-correspond-to-the-button-signals">a series
of handlers correspond to the button signals</h2>
<p>@@<span class="citation" data-cites="include">@include</span>
tfe5/tfeapplication.c open_cb new_cb save_cb close_cb @@@</p>
<p><code>open_cb</code>, <code>new_cb</code>, <code>save_cb</code> and
<code>close_cb</code> just call corresponding notebook page
functions.</p>
<h2 id="meson.build">meson.build</h2>
<p>@@<span class="citation" data-cites="include">@include</span>
tfe5/meson.build @@@</p>
<p>In this file, just the source file names are modified from the prior
version.</p>
<h2 id="source-files">source files</h2>
<p>You can download the files from the <a
href="https://github.com/ToshioCP/Gtk4-tutorial">repository</a>. There
are two options.</p>
<ul>
<li>Use git and clone.</li>
<li>Run your browser and open the <a
href="https://github.com/ToshioCP/Gtk4-tutorial">top page</a>. Then
click on “Code” button and click “Download ZIP” in the popup menu. After
that, unzip the archive file.</li>
</ul>
<p>If you use git, run the terminal and type the following.</p>
<pre><code>$ git clone https://github.com/ToshioCP/Gtk4-tutorial.git</code></pre>
<p>The source files are under /src/tfe5 directory.</p>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
  </body>
  </html>
